package com.ehotting.mqbd.core.manager;

import com.alibaba.fastjson.JSON;
import com.ehotting.mqbd.api.bean.solver.ModuleInfoBean;
import com.ehotting.mqbd.api.bean.solver.ModuleSolverBean;
import com.ehotting.mqbd.api.bean.solver.SolverInfoBean;
import com.ehotting.mqbd.api.bean.solver.SolverStateBean;
import com.ehotting.mqbd.core.config.MqbdCoreServerInfoConfig;
import com.ehotting.mqbd.core.service.SolverInfoService;
import com.ehotting.mqbd.core.service.AgentRefSolverService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class SolverInfoManager {

    private Logger logger = LoggerFactory.getLogger(SolverInfoManager.class);

    private MqbdCoreServerInfoConfig mqbdCorePropertyConfig;

    @Autowired
    private SolverInfoService solverInfoService;

    @Autowired
    private AgentRefSolverService agentRefSolverService;

    private ModuleManager moduleManager;

    public SolverInfoManager(MqbdCoreServerInfoConfig mqbdCorePropertyConfig,ModuleManager moduleManager,SolverInfoService solverInfoService){
        this.mqbdCorePropertyConfig = mqbdCorePropertyConfig;
        this.moduleManager = moduleManager;
        this.solverInfoService = solverInfoService;
    }


    public void loadSolver(){
        ModuleSolverBean moduleSolver = mqbdCorePropertyConfig.getSolver();
        Map<String, List<SolverStateBean>> solverStateMap = solverInfoService.getMapServerInfoList();
        if(solverStateMap==null){
            solverStateMap = new HashMap<>();
        }
        Set<Map.Entry<String,List<SolverInfoBean>>> configEntrySet = moduleSolver.entrySet();
        for(Map.Entry<String,List<SolverInfoBean>> configEntry :  configEntrySet){
            String module = configEntry.getKey();
            List<SolverInfoBean> nacosSolverInfoList = configEntry.getValue();
            log.info("Nacos module[{}],solverInfoList.size():{}",module,nacosSolverInfoList.size());
            if(module==null){
                continue;
            }
            loaderSolverStateMap( module, solverStateMap,  configEntry.getValue());
        }
        this.saveAll(solverStateMap);

        //clearModuleNull();
    }

    private void loaderSolverStateMap(String module,Map<String, List<SolverStateBean>> solverStateMap, List<SolverInfoBean> nacosSolverInfoList){
        ModuleInfoBean moduleInfo = moduleManager.getByModule(module);
        log.info("Loading moduleInfo:{}",JSON.toJSONString(moduleInfo));
        if(solverStateMap.containsKey(module)){
            List<SolverStateBean> solverStateList = solverStateMap.get(module);
            log.info("Cache solverStateList:{}",solverStateList.size());
            appendOrRemove(module,solverStateList, nacosSolverInfoList);
            copyModuleInfoProperty(moduleInfo, solverStateList);
        } else{
            solverStateMap.put(module, createSolverStateList(module,moduleInfo,nacosSolverInfoList));
        }
    }

    private void copyModuleInfoProperty(ModuleInfoBean moduleInfo, List<SolverStateBean> solverStateList){
        solverStateList.stream().forEach(solverState->{
            solverState.setSolveTotal(moduleInfo!=null?moduleInfo.getSolveTotal():1);
        });
    }

    public SolverStateBean get(String module, String ip){
        SolverStateBean solverState = solverInfoService.get(module, ip);
        return solverState;
    }

    public void save(SolverStateBean solverState){
        if(solverState.getModule()==null){
            logger.error("module is null,return.");
            return;
        }
        solverInfoService.save(solverState);
    }

    public Map<String, List<SolverStateBean>> getMapServerInfoList(){
        return solverInfoService.getMapServerInfoList();
    }


    private  List<SolverStateBean> createSolverStateList(String module, ModuleInfoBean moduleInfo, List<SolverInfoBean> serverInfoList){
        return serverInfoList.stream().map(solverInfo->{
            SolverStateBean solverState = new SolverStateBean(module,solverInfo);
            solverState.setSolveTotal(moduleInfo!=null?moduleInfo.getSolveTotal():1);
            return solverState;
        }).collect(Collectors.toList());
    }

    private void clearModuleNull(){
        String module = "null";
        List<SolverStateBean> moduleList = solverInfoService.getByModule(module);
        for(SolverStateBean solverState : moduleList){
            delete(module,solverState);
        }
    }

    private void appendOrRemove(String module, List<SolverStateBean> solverStateList, List<SolverInfoBean> nacosSolverInfoList){
        logger.info("solverStateList.size():{}",solverStateList.size());
        remove(module,solverStateList, nacosSolverInfoList);
        logger.info("remove solverStateList.size():{}",solverStateList.size());
        append(module,solverStateList, nacosSolverInfoList);
        logger.info("append solverStateList.size():{}",solverStateList.size());
    }

    private void append(String module,List<SolverStateBean> solverStateList, List<SolverInfoBean> nacosSolverInfoList ){
        List<SolverStateBean> addList = new ArrayList<>();
        for(SolverInfoBean nacosServerInfo : nacosSolverInfoList){
            boolean isContain = solverStateList.stream().anyMatch(t->{
                log.info("{}-{}-{}", JSON.toJSONString(t.getSolverInfo()),JSON.toJSONString(nacosServerInfo),t.getSolverInfo().equals(nacosServerInfo));
                return t.getSolverInfo().equals(nacosServerInfo);
            });
            if(isContain == false){
                SolverStateBean solverState = new SolverStateBean(module,nacosServerInfo);
                addList.add(solverState);
            }
        }
        solverStateList.addAll(addList);
    }

    private void remove(String module, List<SolverStateBean> solverStateList, List<SolverInfoBean> nacosSolverInfoList){
        List<SolverStateBean> deleteList = new ArrayList<>();
        for(SolverStateBean solverState :  solverStateList){
            boolean isContain = nacosSolverInfoList.stream().anyMatch(t->{
                return t.equals(solverState.getSolverInfo());
            });
            if(isContain==false){
                deleteList.add(solverState);
                this.delete(module,solverState);
            }
        }
        solverStateList.removeAll(deleteList);
    }

    private void saveAll(Map<String, List<SolverStateBean>> solverStateMap){
        Set<Map.Entry<String,List<SolverStateBean>>> solverStateEntrySet = solverStateMap.entrySet();
        for(Map.Entry<String,List<SolverStateBean>> entry: solverStateEntrySet){
            solverInfoService.batchSave(entry.getValue());
        }
    }

    public void delete(String module, SolverStateBean solverState){
        solverInfoService.delete(module,solverState.getSolverInfo().getIp());
    }

    public void delete(String module, String ip){
        solverInfoService.delete( module,  ip);
    }

    public List<SolverStateBean> getByModule(String module){
        return solverInfoService.getByModule( module);
    }

    public void setSolverRefAgentId(String agentId, SolverInfoBean serverInfo){
        agentRefSolverService.setSolverRefAgentId( agentId,  serverInfo);
    }

    public SolverInfoBean getSolverRefAgentId(String agentId){
        return agentRefSolverService.getSolverRefAgentId( agentId);
    }

    public void deleteSolverRefAgentId(String agentId){
        agentRefSolverService.deleteSolverRefAgentId(agentId);
    }

}